#-*- codeing = utf-8 -*-
#@Time : 2020/11/26 13:37
#@Author : 阳某
#@File : 09.正则表达式.py
#@Software : PyCharm

import re
content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师（C++/python） 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师（Python） 赫里普（上海）信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''

# 将文本内容按行放入列表
lines = content.splitlines()
print(lines)
for line in lines:
    print(line)
    # 查找'万/月' 在 字符串中什么地方
    pos2 = line.find('万/月')     #找到了就返回位置，没找到就返回-1
    print('万/月的位置',pos2)
    if pos2 < 0:
        # 查找'万/每月' 在 字符串中什么地方
        pos2 = line.find('万/每月')
        # 都找不到
        if pos2 < 0:
            continue

    # 执行到这里，说明可以找到薪资关键字
    # 接下来分析 薪资 数字的起始位置
    # 方法是 找到 pos2 前面薪资数字开始的位置
    idx = pos2-1

    # 只要是数字或者小数点，就继续往前面找
    while line[idx].isdigit() or line[idx]=='.':
        idx -= 1

    # 现在 idx 指向 薪资数字前面的那个字，
    # 所以薪资开始的 索引 就是 idx+1
    pos1 = idx + 1

    print(line[pos1:pos2])


print('使用正则表达式')
content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师（C++/python） 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师（Python） 赫里普（上海）信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''

import re
# 每个可以出现一次或者0次
for one in  re.findall(r'([\d.]+)万/每{0,1}月', content):
    print(one)


'''
. 表示要匹配除了 换行符 之外的任何 单个 字符。
'''
content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''

import re
p = re.compile(r'.色')
print(p)
print(type(p))
print(p.findall(content))
for one in  p.findall(content):
    print(type(one))
    print(one)


'''
* 表示匹配前面的子表达式任意次，包括0次。
匹配前面一个字符一次或者任意次数

比如，你要从下面的文本中，选择每行逗号后面的字符串内容，包括逗号本身。注意，这里的逗号是中文的逗号。

苹果，是绿色的
橙子，是橙色的
香蕉，是黄色的
乌鸦，是黑色的
猴子，
就可以这样写正则表达式 ，.* 。     中文逗号开头，任意字符任意次数
紧跟在 . 后面， 表示 任意字符可以出现任意次， 所以整个表达式的意思就是在逗号后面的 所有字符，包括逗号
'''

content = '''苹果，是绿色的
橙子，是橙色的
香蕉，是黄色的
乌鸦，是黑色的
猴子，'''

import re
p = re.compile(r'，.*')
for one in  p.findall(content):
    print(one)


'''
+ 表示匹配前面的子表达式一次或多次，不包括0次。
也就是匹配前面的一个字符至少一次
比如，还是上面的例子，你要从文本中，选择每行逗号后面的字符串内容，包括逗号本身。

但是 添加一个条件， 如果逗号后面 没有内容，就不要选择了。

比如，下面的文本中，最后一行逗号后面 没有内容，就不要选择了。

苹果，是绿色的
橙子，是橙色的
香蕉，是黄色的
乌鸦，是黑色的
猴子，
就可以这样写正则表达式 ，.+ 。
'''


'''
问号-匹配0-1次
? 表示匹配前面的子表达式0次或1次。

比如，还是上面的例子，你要从文本中，选择每行逗号后面的1个字符，也包括逗号本身。

苹果，绿色的
橙子，橙色的
香蕉，黄色的
乌鸦，黑色的
猴子，
就可以这样写正则表达式 ，.? 。

验证一下，如下图所示

image

最后一行，猴子逗号后面没有其它字符了，但是?表示匹配1次或0次， 所以最后一行也选中了一个逗号字符。
'''

'''
花括号-匹配指定次数

点击这里，边看视频讲解，边学习以下内容


花括号表示 前面的字符匹配 指定的次数 。

比如 ，下面的文本

红彤彤，绿油油，黑乎乎，绿油油油油
表达式 油{3} 就表示匹配 连续的 油 字 3次

表达式 油{3,4} 就表示匹配 连续的 油 字 至少3次，至多 4 次
'''

# 贪婪模式和非贪婪模式
# 点击这里，边看视频讲解，边学习以下内容
# 我们要把下面的字符串中的所有html标签都提取出来，
# source = '<html><head><title>Title</title>'
# 得到这样的一个列表
# ['<html>', '<head>', '<title>', '</title>']
# 很容易想到使用正则表达式 <.*>
# 写出如下代码
# source = '<html><head><title>Title</title>'
# import re
# p = re.compile(r'<.*>')
# print(p.findall(source))
# 但是运行结果，却是
# ['<html><head><title>Title</title>']
# 怎么回事？ 原来 在正则表达式中， ‘*', ‘+’, ‘?’ 都是贪婪地，使用他们时，会尽可能多的匹配内容，
# 所以， <.*> 中的 星号（表示任意次数的重复），一直匹配到了 字符串最后的 </title> 里面的e。
# 解决这个问题，就需要使用非贪婪模式，也就是在星号后面加上 ? ，变成这样 <.*?>
# 代码改为
# source = '<html><head><title>Title</title>'
# import re
# # 注意多出的问号
# p = re.compile(r'<.*?>')
# print(p.findall(source))
# 再运行一遍，就可以了
source = '<html><head><title>Title</title>'
import re
p = re.compile(r'<.*>')
print(p.findall(source))

p = re.compile(r'<.*?>')
print(p.findall(source))


'''
对元字符的转义

点击这里，边看视频讲解，边学习以下内容


反斜杠 \ 在正则表达式中有多种用途。

比如，我们要在下面的文本中搜索 所有点前面的字符串，也包含点本身

苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的
如果，我们这样写正则表达式 .*. ， 聪明的你肯定发现不对劲。

因为 点 是一个 元字符， 直接出现在正则表达式中，表示匹配任意的单个字符， 不能表示 . 这个字符本身的意思了。

怎么办呢？

如果我们要搜索的内容本身就包含元字符，就可以使用 反斜杠进行转义。

这里我们就应用使用这样的表达式： .*\.
'''
content = '''苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的'''

import re
p = re.compile(r'.*\.')
for one in  p.findall(content):
    print(one)

'''
匹配某种字符类型
反斜杠后面接一些字符，表示匹配 某种类型 的一个字符。

比如
\d{11}连续11个数字
\d 匹配0-9之间任意一个数字字符，等价于表达式 [0-9]

\D 匹配任意一个不是0-9之间的字符，等价于表达式 [^0-9]

\s 匹配任意一个空白字符，包括 空格、tab、换行符等，等价于表达式 [\t\n\r\f\v]

\S 匹配任意一个非空白字符，等价于表达式 [^ \t\n\r\f\v]
# 判断用户名是否符合
\w 匹配任意一个文字字符，包括大小写字母、数字、下划线，等价于表达式 [a-zA-Z0-9_]
re.A表示ASCII 码
缺省情况也包括 Unicode文字字符，如果指定 ASCII 码标记，则只包括ASCII字母

\W 匹配任意一个非文字字符，等价于表达式 [^a-zA-Z0-9_]


反斜杠也可以用在方括号里面，比如 [\s,.] 表示匹配 ： 任何空白字符， 或者逗号，或者点
'''
t = '''
王亚胡
tony
刘文斌
'''
import re
p = re.findall(r'\w{2,4}',t)
print(p)
p = re.findall(r'\w{2,4}',t,re.A)
print(p)

'''
方括号-匹配几个字符之一
点击这里，边看视频讲解，边学习以下内容
方括号表示要匹配 指定的几个字符之一 。
比如
[abc] 可以匹配 a, b, 或者 c 里面的任意一个字符。等价于 [a-c] 。
[a-c] 中间的 - 表示一个范围从a 到 c。
如果你想匹配所有的小写字母，可以使用 [a-z]
一些 元字符 在 方括号内 失去了魔法， 变得和普通字符一样了。
[akm.] 匹配 a k m . 里面任意一个字符
这里 . 在括号里面不在表示 匹配任意字符了，而就是表示匹配 . 这个 字符
如果在方括号中使用 ^ ， 表示 非 方括号里面的字符集合。
'''
content = 'a1b2c3d4e5'

import re
p = re.compile(r'[^\d]' )
for one in  p.findall(content):
    print(one)

t = '''
123456789,
1b2633666,
143552233,
163552233,
183552233,
b25656666,
g25656666,
c25656666,
c25656666c,
0f55d2222,
215475233,
'''
print(re.findall(r'1[26]\d{7}',t))
print(re.findall(r'1[2-8]\d{7}',t))
print(re.findall(r'[a-z]\d{7}',t))
print(re.findall(r'[a-z]\d{8}',t))


'''
^ 表示匹配文本的 开头 位置。
正则表达式可以设定 单行模式 和 多行模式
如果是 单行模式 ，表示匹配 整个文本 的开头位置。
如果是 多行模式 ，表示匹配 文本每行 的开头位置。
比如，下面的文本中，每行最前面的数字表示水果的编号，最后的数字表示价格
001-苹果价格-60，
002-橙子价格-70,
003-香蕉价格-80,
如果我们要提取所有的水果编号，用这样的正则表达式 ^\d+
上面的正则表达式，使用在Python程序里面，如下所示
'''
content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''

import re
p = re.compile(r'^\d+', re.M)#注意，compile 的第二个参数 re.M ，指明了使用多行模式，
for one in  p.findall(content):
    print(one)

import re
p = re.compile(r'^\d+') #单行模式
for one in  p.findall(content):
    print(one)

import re
p = re.compile(r'\d+')
for one in  p.findall(content):
    print(one)


'''
$ 表示匹配文本的 结尾 位置。
如果是 单行模式 ，表示匹配 整个文本 的结尾位置。
如果是 多行模式 ，表示匹配 文本每行 的结尾位置。
比如，下面的文本中，每行最前面的数字表示水果的编号，最后的数字表示价格
001-苹果价格-60，
002-橙子价格-70,
003-香蕉价格-80,
如果我们要提取所有的水果编号，用这样的正则表达式 \d+$
'''

content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''

import re
p = re.compile(r'\d+$', re.MULTILINE)
for one in  p.findall(content):
    print(one)


'''
竖线-匹配其中之一
竖线表示 匹配 其中之一 。
比如 ，
特别要注意的是， 竖线在正则表达式的优先级是最低的， 这就意味着，竖线隔开的部分是一个整体
比如 绿色|橙 表示 要匹配是 绿色 或者 橙 ，
而不是 绿色 或者 绿橙
'''




'''
括号-分组
括号称之为 正则表达式的 组选择。
组 就是把 正则表达式 匹配的内容 里面 其中的某些部分 标记为某个组。
我们可以在 正则表达式中 标记 多个 组
为什么要有组的概念呢？因为我们往往需要提取已经匹配的 内容里面的 某些部分的信心。
前面，我们有个例子，从下面的文本中，选择每行逗号前面的字符串，也 包括逗号本身 。
苹果，苹果是绿色的
橙子，橙子是橙色的
香蕉，香蕉是黄色的
就可以这样写正则表达式 ^.*， 。
但是，如果我们要求 不要包括逗号 呢？
当然不能直接 这样写 ^.*
因为最后的逗号 是 特征 所在， 如果去掉它，就没法找 逗号前面的了。

但是把逗号放在正则表达式中，又会包含逗号。

解决问题的方法就是使用 组选择符 ： 括号。

我们这样写 ^(.*)，
'''


content = '''苹果，苹果是绿色的
橙子，橙子是橙色的
香蕉，香蕉是黄色的'''

import re
p = re.compile(r'^(.*)，', re.MULTILINE)
for one in  p.findall(content):
    print(one)


content = '''张三，手机号码15945678901
李四，手机号码13945677701
王二，手机号码13845666901'''

import re
p = re.compile(r'^(.+)，.+(\d{11})', re.MULTILINE)
for one in  p.findall(content):
    print(one)

content = '''张三，手机号码15945678901
李四，手机号码13945677701
王二，手机号码13845666901'''

import re
p = re.compile(r'^(?P<name>.+)，.+(?P<phone>\d{11})', re.MULTILINE)
for match in  p.finditer(content):
    print(match.group('name'))
    print(match.group('phone'))



'''
切割字符
字符串 对象的 split 方法只适用于 简单的字符串分割。 有时，你需要更加灵活的字符串切割。
比如，我们需要从下面字符串中提取武将的名字。
names = '关羽; 张飞, 赵云,马超, 黄忠  李逵'
我们发现这些名字之间， 有的是分号隔开，有的是逗号隔开，有的是空格隔开， 而且分割符号周围还有不定数量的空格
这时，可以使用正则表达式里面的 split 方法：
import re
names = '关羽; 张飞, 赵云,   马超, 黄忠  李逵'
namelist = re.split(r'[;,\s]\s*', names)
print(namelist)
# 正则表达式 [;,\s]\s* 指定了，分割符为 分号、逗号、空格 里面的任意一种均可，并且 该符号周围可以有不定数量的空格。
'''

import re
names = '关羽; 张飞, 赵云,   马超, 黄忠  李逵'
namelist = re.split(r'[;,\s]\s*', names)
print(namelist)



'''
让点匹配换行
前面说过, 点 是 不匹配换行符 的，可是有时候，特征 字符串就是跨行的，比如要找出下面文字中所有的职位名称
如果你直接使用表达式 class=\"t1\">.*?<a>(.*?)</a> 会发现匹配不上，因为 t1 和 <a> 之间有两个空行。

这时你需要 点也匹配换行符 ，可以使用 DOTALL 参数
'''



content = '''
<div class="el">
        <p class="t1">           
            <span>
                <a>Python开发工程师</a>
            </span>
        </p>
        <span class="t2">南京</span>
        <span class="t3">1.5-2万/月</span>
</div>
<div class="el">
        <p class="t1">
            <span>
                <a>java开发工程师</a>
            </span>
		</p>
        <span class="t2">苏州</span>
        <span class="t3">1.5-2/月</span>
</div>
'''

import re
p = re.compile(r'class=\"t1\">.*?<a>(.*?)</a>', re.DOTALL)
for one in  p.findall(content):
    print(one)

p = re.compile(r'class=\"t1\">.*?<a>(.*?)</a>', re.S)
for one in  p.findall(content):
    print(one)



'''
字符串替换
匹配模式替换
字符串 对象的 replace 方法只适应于 简单的 替换。 有时，你需要更加灵活的字符串替换。
比如，我们需要在下面这段文本中 所有的 链接中 找到所以 /avxxxxxx/ 这种 以 /av 开头，后面接一串数字， 这种模式的字符串。
然后，这些字符串全部 替换为 /cn345677/ 
被替换的内容不是固定的，所以没法用 字符串的replace方法。
这时，可以使用正则表达式里面的 sub 方法：
sub 方法就是也是替换 字符串， 但是被替换的内容 用 正则表达式来表示 符合特征的所有字符串。
比如，这里就是第一个参数 /av\d+?/ 这个正则表达式，表示以 /av 开头，后面是一串数字，再以 / 结尾的 这种特征的字符串 ，是需要被替换的。
第二个参数，这里 是 '/cn345677/' 这个字符串，表示用什么来替换。
第三个参数是 源字符串。
'''



import re

names = '''

下面是这学期要学习的课程：

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里，边看视频讲解，边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里，边看视频讲解，边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里，边看视频讲解，边学习以下内容</a>
这节讲的是切割磁力线
'''
newStr = re.sub(r'/av\d+?/', '/cn345677/' , names)
print(newStr)



'''
指定替换函数
点击这里，边看视频讲解，边学习以下内容


刚才的例子中，我们用来替换的是一个固定的字符串 /cn345677/。

如果，我们要求，替换后的内容 的是原来的数字+6， 比如 /av66771949/ 替换为 /av66771955/ 。

怎么办？

这种更加复杂的替换，我们可以把 sub的第2个参数 指定为一个函数 ，该函数的返回值，就是用来替换的字符串。
'''